unit uMainFrm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,

  GlScene, GlObjects, GlCadencer, GLWin32Viewer, GLRenderContextInfo, GlWindowsFont, GlHudObjects,
  GlMaterial,
  VectorGeometry,
  uBaseButton,

  uTweener;
type
  THero = class
    fSprite: TGlHudSprite;
    fX: Single;
    fAlpha: Single;
  end;

  TfrmMain = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    {Main Objects}
    fGlScene: TGlScene;
    fCadencer: TGLCadencer;
    fViewer: TGLSceneViewer;
    fCamera: TGlCamera;
    fMainDummy: TGlDummyCube;
    fFpsTimer: Single;
    fMatLib: TGlMaterialLibrary;

    {Text Objects}
    fWinFont: TGLWindowsBitmapFont;
    fHudText: TGLHUDText;
    fBack: TGlHudSprite;

    {SimpleButton}
    fRightBtn: TGUIAlphaButton;
    fLeftBtn: TGUIAlphaButton;

    {Tweener}
    fActiveHero: integer;
    fHeroes: TList;
    fTweener: TTweener;
  protected  
    Procedure UpdateHeroes;
    Procedure ActivateHero(aIndex: integer; aDirection: integer);
    Procedure OnNextClick(aSender: TGUIBaseInteractiveObject);
    Procedure OnPrevClick(aSender: TGUIBaseInteractiveObject);
  public
    Procedure InitFontAndSprites;
    Procedure InitMaterials;
    Procedure InitTweener;
    Procedure OnCadencerProgress(Sender : TObject; const deltaTime, newTime : Double);
  end;

var
  frmMain: TfrmMain;

implementation
uses
  glKeyboard, GLCrossPlatform,
  uDemoInit;
{$R *.dfm}

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  fFpsTimer := 0;
  CreateDemo(self, fGlScene, fCadencer, fViewer);
  
  fCamera := TGlCamera.CreateAsChild(fGlScene.Objects);
  with fCamera do
  begin
    Position.SetPoint(0, 0, 5);
    Direction.SetVector(0, 0, -1);
    Up.SetVector(0, 1, 0);
    CameraStyle := csOrthogonal;
    SceneScale := 0.1;
  end;

  fMainDummy := TGLDummyCube.CreateAsChild(fGlScene.Objects);
  fMainDummy.ObjectsSorting := osNone;

  fViewer.Camera := fCamera;
  fCadencer.OnProgress := OnCadencerProgress;

  fMatLib := TGlMaterialLibrary.Create(self);

  InitMaterials;
  InitTweener;
  InitFontAndSprites;
end;

procedure TfrmMain.FormActivate(Sender: TObject);
begin
  fCadencer.Enabled := true;
end;

Procedure TfrmMain.InitFontAndSprites;
  Function AddSprite(aMatName: String; aX, aY: integer; aW, aH: Integer): TGlHudSprite;
  begin
    result := TGlHudSprite.CreateAsChild(fMainDummy);
    with result do
    begin
      Material.LibMaterialName := aMatName;
      Material.MaterialLibrary := fMatLib;
      Width  := aW;
      Height := aH;
      Position.SetPoint(aX, aY, 0);
    end;
  end;

  Function AddHero(aMatName: String; aAlpha: Single = 1): THero;
  begin
    result := THero.Create;
    result.fSprite := TGlHudSprite.CreateAsChild(fMainDummy);
    with result.fSprite do
    begin
      Material.LibMaterialName := aMatName;
      Material.MaterialLibrary := fMatLib;
      Width  := Material.GetActualPrimaryTexture.Image.Width;
      Height := Material.GetActualPrimaryTexture.Image.Height;
      Position.SetPoint(300, 200, 0);
      AlphaChannel := aAlpha;
      Material.GetActualPrimaryMaterial.FrontProperties.Diffuse.Alpha := aAlpha;
    end;
    result.fX := 300;
    result.fAlpha := aAlpha;
    fHeroes.Add(result);
  end;
begin
  fWinFont := TGLWindowsBitmapFont.Create(self);
  fWinFont.Font.Name := 'Arial';

  fBack := AddSprite('back_1', 300, 200, 600, 400);

  fHudText := TGLHUDText.CreateAsChild(fMainDummy);
  with fHudText do
  begin
    BitmapFont := fWinFont;
    Text := 'Lampogolovii presents ''Animated Button Demo''';
    Position.SetPoint(590, 380, 0);
    ModulateColor.SetColor(92/255, 165/255, 177/255, 1);
    Alignment := taRightJustify;
  end;

  AddHero('dog', 0);
  AddHero('cat', 0);
  AddHero('coon', 0);

  fRightBtn := TGUIAlphaButton.CreateAsChild(fMainDummy);
  fRightBtn.SetMaterials('btn_1', 'btn_2', fMatLib);
  fRightBtn.Position.SetPoint(435, 200, 0);
  fRightBtn.OnMouseClick := OnNextClick;
  fRightBtn.Show;

  fLeftBtn := TGUIAlphaButton.CreateAsChild(fMainDummy);
  fLeftBtn.SetMaterials('btn_3', 'btn_4', fMatLib);
  fLeftBtn.Position.SetPoint(140, 200, 0);
  fLeftBtn.OnMouseClick := OnPrevClick;
  fLeftBtn.Show;

  ActivateHero(0, -1);
end;

Procedure TfrmMain.InitMaterials;
begin
  AddMaterials(fMatLib, str_ImagesFolder + '\AnimatedButton\',
               ['back_1', 'btn_1', 'btn_2', 'btn_3', 'btn_4'],
               ['back_1', 'btn_1', 'btn_2', 'btn_3', 'btn_4']);

  AddMaterials(fMatLib, str_ImagesFolder + '\AnimatedButton\',
               ['dog', 'cat', 'coon'],
               ['dog', 'cat', 'coon']);
end;

Procedure TfrmMain.InitTweener;
begin
  fTweener := TTweener.Create;
  fHeroes := TList.Create;
end;

Procedure TfrmMain.ActivateHero(aIndex: integer; aDirection: integer);
begin
  if (fActiveHero >= 0) then
    with THero(fHeroes[fActiveHero]) do
    begin
      fTweener.DeletePSingle(@fX);
      fTweener.DeletePSingle(@fAlpha);
      fTweener.AddTweenPSingle(@fX, ts_ExpoEaseIn, fX, 300 + aDirection * 100, 2);
      fTweener.AddTweenPSingle(@fAlpha, ts_ExpoEaseIn, fAlpha, 0, 0.7);
    end;

  if(aIndex >= 0) then
    with THero(fHeroes[aIndex]) do
    begin
      fTweener.DeletePSingle(@fX);
      fTweener.DeletePSingle(@fAlpha);
      fTweener.AddTweenPSingle(@fX, ts_ExpoEaseIn, 300 - aDirection * 100, 300, 2, 0.5);
      fTweener.AddTweenPSingle(@fAlpha, ts_ExpoEaseIn, 0, 1, 0.7, 0.5);
    end;

  fActiveHero := aIndex;
end;

Procedure TfrmMain.OnNextClick(aSender: TGUIBaseInteractiveObject);
begin
  if(fActiveHero = fHeroes.Count - 1)then
    ActivateHero(0, -1)
  else
    ActivateHero(fActiveHero + 1, -1);
end;

Procedure TfrmMain.OnPrevClick(aSender: TGUIBaseInteractiveObject);
begin
  if(fActiveHero = 0)then
    ActivateHero(fHeroes.Count - 1, 1)
  else
    ActivateHero(fActiveHero - 1, 1);
end;

Procedure TfrmMain.UpdateHeroes;
var
  i: integer;
begin
  for i := 0 to fHeroes.Count - 1 do
    with THero(fHeroes[i]) do
    begin
      fSprite.Position.SetPoint(fX, fSprite.Position.y, 0);
      //fSprite.AlphaChannel := fAlpha;
      fSprite.Material.GetActualPrimaryMaterial.FrontProperties.Diffuse.Alpha := fAlpha;
    end;
end;

Procedure TfrmMain.OnCadencerProgress(Sender : TObject; const deltaTime, newTime : Double);
var
  MPos: TPoint;
begin
  fTweener.Update(deltaTime);
  UpdateHeroes();

  GetCursorPos(Mpos);
  MPos := fViewer.ScreenToClient(MPos);

  fRightBtn.SetMouseState(MPos.x, MPos.y, IsKeyDown(vk_LButton));
  fLeftBtn.SetMouseState(MPos.x, MPos.y, IsKeyDown(vk_LButton));
  
  fViewer.Invalidate;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  FreeAndNil(fTweener);
end;

end.
